﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;
using SmallBasicFun.Analytics;

namespace GaDotNet.Common.Data
{
	
	public class TrackingRequest
	{
		private readonly GooglePageView googlePageView;

		public static Func<Random> GetRandom = () => new Random(); 
		public static Func<DateTime> GetDate = () => DateTime.Now; 

		public string RequestedByIpAddress;

		public string ReferralSource = "(direct)";
		public string Medium = "(none)";
		public string Campaign = "(direct)";

		public GoogleEvent TrackingEvent;
	


		public string AnalyticsAccountCode;

		private string timeStampCurrent = ConvertToUnixTimestamp(GetDate()).ToString();
		private string visitCount = "2";

		public class GoogleCodes
		{
			public const string AnalyticsVersion = "utmwv";
			public static string RequestNumber = "utmn";
			public static string DomainName = "utmhn";
			public static string DocumentEncoding = "utmcs";
			public static string ScreenResolution = "utmsr";
			public static string ScreenColorDepth = "utmsc";
			public static string UserLanguage = "utmul";
			public static string JavaEnabled = "utmje";
			public static string FlashVersion = "utmfl";
			public static string GooglePageTitle = "utmdt";
			public static string HitId = "utmhid";
			public static string ReferrerUrl = "utmr";
			public static string GooglePageUrl = "utmp";
			public static string AccountId = "utmac";
			public static string AnalyticsCookieString = "utmcc";
		}

		public TrackingRequest(GooglePageView googlePageView)
		{
			this.googlePageView = googlePageView;
		}


		private int DomainHash
		{
			get
			{
				return GetDomainHashFor(googlePageView.DomainName);
			}
		}

		public static int GetDomainHashFor(string domainName)
		{
			if (domainName != null)
			{
				// converted from the google domain hash code listed here:
				// http://www.google.com/support/forum/p/Google+Analytics/thread?tid=626b0e277aaedc3c&hl=en
				int a = 0;
				int h;
				char chrCharacter;
				int intCharacter;
				for (h = domainName.Length - 1; h >= 0; h--)
				{
					chrCharacter = char.Parse(domainName.Substring(h, 1));
					intCharacter = (int) chrCharacter;
					a = (a << 6 & 268435455) + intCharacter + (intCharacter << 14);
					int c = a & 266338304;
					a = c != 0 ? a ^ c >> 21 : a;
				}

				return a;
			}
			return 0;
		}

		//the cookie collection string (we fake it)
		private string UtmcCookieString
		{
			get
			{
				Random randomNumber = GetRandom();


				string utma = String.Format("{0}.{1}.{2}.{3}.{4}.{5}",
				                            DomainHash,
				                            int.Parse(randomNumber.Next(1000000000).ToString()),
				                            timeStampCurrent,
				                            timeStampCurrent,
				                            timeStampCurrent,
				                            visitCount);

				//referral informaiton
				string utmz = String.Format("{0}.{1}.{2}.{3}.utmcsr={4}|utmccn={5}|utmcmd={6}",
				                            DomainHash,
				                            timeStampCurrent,
				                            "1",
				                            "1",
				                            ReferralSource,
				                            Campaign,
				                            Medium);

				//return String.Format("__utma%3D{0}.{1}.{2}.{3}.{4}.{5}",)))
				string utmcc = Uri.EscapeDataString(String.Format("__utma={0};+__utmz={1};",
				                                                  utma,
				                                                  utmz
					                                    ));

				return (utmcc);
			}
		}

		public Uri TrackingGifUri
		{
			get { return new Uri(TrackingGifURL); }
		}

		public string TrackingGifURL
		{
			get
			{
				Random randomNumber = GetRandom();


				List<KeyValuePair<string, string>> paramList = new List<KeyValuePair<string, string>>
					{
						KeyPair(GoogleCodes.AnalyticsVersion, "4.7.2"), // Analytics version
						KeyPair(GoogleCodes.RequestNumber, randomNumber.Next(1000000000).ToString()), // Random request number
						KeyPair(GoogleCodes.DomainName, googlePageView.DomainName ?? string.Empty), // Your domain name
						KeyPair(GoogleCodes.DocumentEncoding, "UTF-8"), // Document encoding
						KeyPair(GoogleCodes.ScreenResolution, "-"), // Screen Resolution
						KeyPair(GoogleCodes.ScreenColorDepth, "-"), // Screen Resolution
						KeyPair(GoogleCodes.UserLanguage, "-"), // user language
						KeyPair(GoogleCodes.JavaEnabled, "0"), // java enabled or not
						KeyPair(GoogleCodes.FlashVersion, "-"), // user flash version
						KeyPair(GoogleCodes.GooglePageTitle, googlePageView.GetPageTitleUrlEncoded()),
						// page title
						KeyPair(GoogleCodes.HitId, randomNumber.Next(1000000000).ToString()), // page title
						KeyPair(GoogleCodes.ReferrerUrl, "-"), // referrer URL
						KeyPair(GoogleCodes.GooglePageUrl, googlePageView.Url), // document page URL (relative to root)
						KeyPair(GoogleCodes.AccountId, AnalyticsAccountCode ?? string.Empty), // Your GA account code
						KeyPair(GoogleCodes.AnalyticsCookieString, UtmcCookieString) // cookie string (encoded)
					};

				//check if our tracking event is null and if not add to the params
				if (TrackingEvent != null)
				{
					TrackingEvent.Validate();

					//taken from http://code.google.com/apis/analytics/docs/tracking/gaTrackingTroubleshooting.html
					string eventString = String.Format("5({0}*{1}*{2})({3})",
					                                   TrackingEvent.Category,
					                                   TrackingEvent.Action,
					                                   TrackingEvent.Label,
					                                   TrackingEvent.Value
						);

					paramList.Add(new KeyValuePair<string, string>("utme", Uri.EscapeDataString(eventString)));

					paramList.Add(new KeyValuePair<string, string>("gaq", "1"));

					paramList.Add(new KeyValuePair<string, string>("utmt", "event")); // type of request (page view or event etc)
				}


				//add ip address if we have one
				if (!String.IsNullOrEmpty(RequestedByIpAddress))
				{
					paramList.Add(new KeyValuePair<string, string>("utmip", RequestedByIpAddress));
				}


				//get final param string
				StringBuilder GaParams = new StringBuilder();
				foreach (KeyValuePair<string, string> pair in paramList)
				{
					GaParams.Append(String.Format("{0}={1}&", pair.Key, pair.Value));
				}
				string paramsFinal = GaParams.ToString();
				paramsFinal = paramsFinal.Substring(0, paramsFinal.Length - 1);

				var url =  String.Format("http://www.google-analytics.com/__utm.gif?{0}",paramsFinal);
				return url;
			}
		}

		private KeyValuePair<string, string> KeyPair(string googleCode, string value)
		{
			return new KeyValuePair<string, string>(googleCode, value);
		}

		public void Validate()
		{
			googlePageView.Validate();
			if (String.IsNullOrEmpty(AnalyticsAccountCode))
			{
				throw new ArgumentException("'AnalyticsAccountCode' requires a value", "AnalyticsAccountCode");
			}
		}
		
		public void FireTrackingEvent()
		{
			Debug.Print("tracking");
			using (WebResponse response = WebRequest.Create(TrackingGifUri).GetResponse())
			{
				Debug.Print(response.ToString());
			}
		}
		public static int ConvertToUnixTimestamp(DateTime value)
		{
			return (int)(value - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds;
		}
	}
}